package kassiopeia.plugin.crawler.extractor;

import kassiopeia.plugin.Context;
import kassiopeia.plugin.Event;
import kassiopeia.plugin.PluginException;
import kassiopeia.plugin.ProcessorPlugin;
import net.htmlparser.jericho.Element;
import net.htmlparser.jericho.HTMLElementName;
import net.htmlparser.jericho.Source;
import org.apache.log4j.Logger;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

public class ExtractorPlugin extends ProcessorPlugin {

    private final Logger logger = Logger.getLogger(ExtractorPlugin.class);

    // Outputs
    public static final String URL_OUTPUT = "out";

    // Event headers
    public static final String URL_HEADER_NAME = "URL";

    // Constructor for testing purposes only
    public ExtractorPlugin(Context context) {
        super(context);
    }

    public ExtractorPlugin() {}

    @Override
    public void process(Event event) {
        byte[] pageContent = getNotNullableEventBody(event, byte[].class);
        URL url = getNotNullableEventHeader(event, URL_HEADER_NAME, URL.class);
        String urlString = url.toExternalForm();

        logger.debug("Extracting links from: " + urlString);

        try {
            extractLinks(url, pageContent);
        } catch(IOException exception) {
            throw new PluginException("Error while parsing page content (" + urlString + ")", exception);
        }

        logger.debug("Extracting links from: " + urlString + " done.");
    }

    private void extractLinks(URL url, byte[] pageContent) throws IOException {
        Source source = new Source(new ByteArrayInputStream(pageContent));
        List<Element> elements = source.getAllElements(HTMLElementName.A);
        for(Element element : elements) {
            String link = element.getAttributeValue("href");
            if(link != null && !link.isEmpty()) {
                createAndSendEvent(url, link);
            }
        }
    }

    private void createAndSendEvent(URL contextUrl, String link) {
        try {
            URL normalizedUrl = normalizeUrl(contextUrl, link);
            logger.debug("Found link: " + normalizedUrl.toExternalForm());
            Event outgoingEvent = new Event(normalizedUrl);
            getContext().sendLocally(outgoingEvent, URL_OUTPUT);
        } catch(MalformedURLException exception) {
            logger.debug("Ignoring malformed URL (" + contextUrl + "," + link + ")");
        }
    }

    private static URL normalizeUrl(URL context, String urlString) throws MalformedURLException {
        return new URL(context, urlString);
    }
}
